#include <Client.h>
#include <cstdlib>			// exit(), atoi()
#include <cstring>			// strlen()
#include <process.h>
#include <ctime>
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <Threading.h>
#include <openssl/rc4.h>
using namespace std;
#define NUMBEROFCLIENTS 1
char* Encrypt(unsigned char *keydata, char *plaintext, int Length)
{
	char *encrypted = new char[Length+1];
	RC4_KEY key;
	RC4_set_key(&key, strlen((const char*)keydata), keydata);

	// Encryption
	RC4(&key, Length, (const unsigned char*)plaintext, (unsigned char*)encrypted);
	encrypted[Length] = '\0';

	return encrypted;
}

int main()
{ 
	/** Creating multiple objects **/
	WindowsThreading *Obj = new WindowsThreading[NUMBEROFCLIENTS];
	
	/** setting the values **/
	Obj[0].SetNumberOfThreads(2);
	Obj[0].SetRowsMatrixA(50);
	Obj[0].SetColumsMatrixA(30);	
	Obj[0].SetRowsMatrixB(30);
	Obj[0].SetColumsMatrixB(70);

	/** Dynamically Assigning memory **/
	Obj[0].AssignMemory(MATRIXA);
	Obj[0].AssignMemory(MATRIXB);
	//Obj[0].AssignMemory(MATRIXC);

	/** Setting Matrix A and B with Random values **/
	Obj[0].MatrixGeneration(MATRIXA);
	Obj[0].MatrixGeneration(MATRIXB);
	if(Obj[0].GetColumsMatrixA()!=Obj[0].GetRowsMatrixB())
	{
		cout<<"multiplication not possible"<<endl;
		return 0;
	}

	// Create Client object.
	Client ClientObj;

	// Create Client Socket.
	ClientObj.CreateSocket(TCPSOCKET);
	ClientObj.SetSocketOptions();

	// Initialize and bind Client address.
	ClientObj.InitialiseAddress(DEFAULTCLIENTPORT);	// Without any argument default port will be chosen.
	ClientObj.Bind();

	char ServerName[24];
	int ServerPort;
	cout << "Enter Server name or IP: "; // Use localhost or 127.0.0.1 for local server.
	cin.getline(ServerName, 24);
	cout << "Enter Server port: ";
	cin >> ServerPort;

	// Connect to Server. Server name/IP and port are provided as arguments.
	ClientObj.Connect(ServerName, ServerPort);

	/**Send**/
	//SENDING MATRIX A
	//int temp;
	int matrix_A_rows,matrix_A_colums;
	matrix_A_rows=Obj[0].GetRowsMatrixA();
	char buffer[sizeof(int)]; // buffer for matrix_A_rows
	ClientObj.memory_copy(&buffer, &matrix_A_rows, sizeof(int));
	
	unsigned char keydata[] = "password";
	//char plaintext[]="Aneela";

	//int Length = strlen(plaintext);

	char *Encrypted = Encrypt(keydata,(buffer), strlen(buffer));
	//char *Decrypted = Encrypt(keydata, Encrypted, Length);

	ClientObj.Send((void*)keydata,sizeof(int));

	matrix_A_colums=Obj[0].GetColumsMatrixA();
	unsigned char buffer1[sizeof(int)];// buffer1 for matrix_A_columns
	ClientObj.memory_copy(&buffer1, &matrix_A_colums, sizeof(int));
	ClientObj.Send((void*)buffer1,sizeof(buffer1));
	
	//SENDING MATRIX B
	int matrix_B_rows,matrix_B_colums;
	matrix_B_rows=Obj[0].GetRowsMatrixB();
	unsigned char buffer2[sizeof(int)];// buffer12 for matrix_B_rows
	ClientObj.memory_copy(&buffer2, &matrix_B_rows, sizeof(int));

	ClientObj.Send((void*)buffer2,sizeof(buffer2));
	matrix_B_colums=Obj[0].GetColumsMatrixB();
	unsigned char buffer3[sizeof(int)];// buffer3 for matrix_B_columns
	ClientObj.memory_copy(&buffer3, &matrix_B_colums, sizeof(int));
	ClientObj.Send((void*)buffer3,sizeof(buffer3));
	
	int matrixA_length;
	matrixA_length=Obj[0].GetColumsMatrixA()* Obj[0].GetRowsMatrixA();
	unsigned char *matrixA_buffer= new unsigned char[sizeof(int)*matrixA_length];
	ClientObj.memory_copy(matrixA_buffer, Obj[0].GetMatrixA(), sizeof(int)*matrixA_length);
	ClientObj.Send((void*)matrixA_buffer,sizeof(int)*matrixA_length);//sending matrix

	int matrixB_length;
	matrixB_length=Obj[0].GetColumsMatrixB()* Obj[0].GetRowsMatrixB();
	unsigned char *matrixB_buffer= new unsigned char[sizeof(int)*matrixB_length];
	ClientObj.memory_copy(matrixB_buffer, Obj[0].GetMatrixB(), sizeof(int)*matrixB_length);
	ClientObj.Send((void*)matrixB_buffer,sizeof(int)*matrixB_length);
	
	//receive.
	int* recieved_Matrix_C;
	ClientObj.Receive();
	char* recieved_buffer=ClientObj.GetBuffer();
	recieved_Matrix_C = (int*)recieved_buffer;
	Obj[0].SetMatrixC( recieved_Matrix_C );

	/** Storing to file just for checking**/
	Obj[0].MatrixStore(MATRIXA);
	Obj[0].MatrixStore(MATRIXB);
	Obj[0].MatrixStore(MATRIXC);

//***DELETING ALLOCATED MEMORIES
	Obj[0].DeleteMemory(MATRIXA);
	Obj[0].DeleteMemory(MATRIXB);
	delete matrixA_buffer;
	delete matrixB_buffer;

	ClientObj.CloseClientSocket();// CLOSING CLIENT SOCKET

	return 0;
}
